package com.framework.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.framework.core.common.enums.StatusEnum;
import com.framework.core.exception.CustomException;
import com.framework.system.entity.*;
import com.framework.system.entity.dto.SysRoleAddDTO;
import com.framework.system.entity.dto.SysRoleAssignMenuDTO;
import com.framework.system.entity.dto.SysRoleEditDTO;
import com.framework.system.entity.dto.SysRoleQueryDTO;
import com.framework.system.entity.vo.SysDeptVO;
import com.framework.system.entity.vo.SysMenuVO;
import com.framework.system.entity.vo.SysRoleListVO;
import com.framework.system.entity.vo.SysRoleVO;
import com.framework.system.mapper.*;
import com.framework.system.service.ISysRoleService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author Kevin
 * @since 2021-06-10
 */
@Service
@AllArgsConstructor
public class SysRoleServiceImpl implements ISysRoleService {

    private SysRoleMapper sysRoleMapper;

    private SysUserRoleMapper sysUserRoleMapper;

    private SysRoleDeptMapper sysRoleDeptMapper;

    private SysRoleMenuMapper sysRoleMenuMapper;

    private SysDeptMapper sysDeptMapper;

    private SysMenuMapper sysMenuMapper;

    @Override
    public Page<SysRoleListVO> selectPage(Page reqPage, SysRoleQueryDTO req) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getRoleCode()), SysRole::getRoleCode, req.getRoleCode());
        queryWrapper.like(StrUtil.isNotBlank(req.getRoleName()), SysRole::getRoleName, req.getRoleName());
        queryWrapper.orderByAsc(SysRole::getSort);
        Page<SysRole> page = sysRoleMapper.selectPage(reqPage, queryWrapper);
        Page<SysRoleListVO> voPage = BeanUtil.copyProperties(page, Page.class);
        voPage.setRecords(BeanUtil.copyToList(page.getRecords(), SysRoleListVO.class));
        return voPage;
    }

    @Override
    public List<SysRoleListVO> selectList(SysRoleQueryDTO req) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getRoleCode()), SysRole::getRoleCode, req.getRoleCode());
        queryWrapper.like(StrUtil.isNotBlank(req.getRoleName()), SysRole::getRoleName, req.getRoleName());
        queryWrapper.orderByAsc(SysRole::getSort);
        List<SysRole> list = sysRoleMapper.selectList(queryWrapper);
        return BeanUtil.copyToList(list, SysRoleListVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysRoleAddDTO req) {
        if (!this.checkUniqueRoleName(req.getRoleName(), null)) {
            throw new CustomException("角色名称已存在");
        }
        if (!this.checkUniqueRoleCode(req.getRoleCode(), null)) {
            throw new CustomException("角色编码已存在");
        }
        SysRole entity = BeanUtil.copyProperties(req, SysRole.class);
        sysRoleMapper.insert(entity);
        // 删除角色和部门关联
        sysRoleDeptMapper.delete(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId, req.getId()));
        // 新增角色和菜单关联
        if (Objects.nonNull(req.getDeptIds())) {
            req.getDeptIds().forEach(item -> {
                SysRoleDept sysRoleDept = new SysRoleDept();
                sysRoleDept.setRoleId(entity.getId());
                sysRoleDept.setDeptId(item);
                sysRoleDeptMapper.insert(sysRoleDept);
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysRoleEditDTO req) {
        if (!this.checkUniqueRoleName(req.getRoleName(), req.getId())) {
            throw new CustomException("角色名称已存在");
        }
        if (!this.checkUniqueRoleCode(req.getRoleCode(), req.getId())) {
            throw new CustomException("角色编码已存在");
        }
        SysRole entity = BeanUtil.copyProperties(req, SysRole.class);
        sysRoleMapper.updateById(entity);
        // 删除角色和部门关联
        sysRoleDeptMapper.delete(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId, req.getId()));
        // 新增角色和菜单关联
        if (Objects.nonNull(req.getDeptIds())) {
            req.getDeptIds().forEach(item -> {
                SysRoleDept sysRoleDept = new SysRoleDept();
                sysRoleDept.setRoleId(entity.getId());
                sysRoleDept.setDeptId(item);
                sysRoleDeptMapper.insert(sysRoleDept);
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(String ids) {
        List<String> idList = Arrays.asList(ids.split(","));
        idList.forEach(item -> {
            SysRole sysRole = sysRoleMapper.selectById(item);
            SysUserRole sysUserRole = sysUserRoleMapper.selectOne(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getRoleId, item));
            if (Objects.nonNull(sysUserRole)) {
                throw new CustomException(String.format("角色【%s】存在用户，无法删除", sysRole.getRoleName()));
            }
            SysRoleDept sysRoleDept = sysRoleDeptMapper.selectOne(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId, item));
            if (Objects.nonNull(sysRoleDept)) {
                throw new CustomException(String.format("角色【%s】已被使用，无法删除", sysRole.getRoleName()));
            }
        });
        idList.forEach(item -> {
            sysRoleMapper.deleteById(item);
        });
    }

    @Override
    public SysRoleVO view(String id) {
        SysRole entity = sysRoleMapper.selectById(id);
        return BeanUtil.copyProperties(entity, SysRoleVO.class);
    }

    @Override
    public List<SysRoleVO> listOptions() {
        List<SysRole> list = sysRoleMapper.selectList(Wrappers.lambdaQuery(SysRole.class)
                .eq(SysRole::getStatus, StatusEnum.YES.getCode())
                .orderByAsc(SysRole::getSort));
        return BeanUtil.copyToList(list, SysRoleVO.class);
    }

    @Override
    public void assignMenu(SysRoleAssignMenuDTO req) {
        // 删除角色和菜单关联
        sysRoleMenuMapper.delete(Wrappers.lambdaQuery(SysRoleMenu.class).eq(SysRoleMenu::getRoleId, req.getRoleId()));
        // 新增角色和菜单关联
        if (Objects.nonNull(req.getMenuIds())) {
            req.getMenuIds().forEach(item -> {
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setRoleId(req.getRoleId());
                sysRoleMenu.setMenuId(item);
                sysRoleMenuMapper.insert(sysRoleMenu);
            });
        }
    }

    @Override
    public List<SysMenuVO> listRoleMenus(String roleId) {
        List<SysRoleMenu> sysRoleMenuList = sysRoleMenuMapper.selectList(Wrappers.lambdaQuery(SysRoleMenu.class).eq(SysRoleMenu::getRoleId, roleId));
        List<SysMenu> sysMenuList = sysRoleMenuList.stream().map(item ->
                sysMenuMapper.selectById(item.getMenuId())
        ).collect(Collectors.toList());
        return BeanUtil.copyToList(sysMenuList, SysMenuVO.class);
    }

    @Override
    public List<SysDeptVO> listRoleDepts(String roleId) {
        List<SysRoleDept> sysRoleDeptList = sysRoleDeptMapper.selectList(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId, roleId));
        List<SysDept> sysDeptList = sysRoleDeptList.stream().map(item ->
                sysDeptMapper.selectById(item.getDeptId())
        ).collect(Collectors.toList());
        return BeanUtil.copyToList(sysDeptList, SysDeptVO.class);
    }

    @Override
    public List<SysRole> listSysRoleByUserId(Long userId) {
        List<SysUserRole> sysUserRoleList = sysUserRoleMapper.selectList(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, userId));
        if (sysUserRoleList.isEmpty()) {
            return new ArrayList();
        }
        List<Long> roleIdList = sysUserRoleList.stream().map(item -> item.getRoleId()).collect(Collectors.toList());
        List<SysRole> sysRoleList = sysRoleMapper.selectList(Wrappers.lambdaQuery(SysRole.class)
                .in(SysRole::getId, roleIdList)
                .eq(SysRole::getStatus, StatusEnum.YES.getCode()));
        return sysRoleList;
    }

    @Override
    public List<SysRoleVO> selectOptions() {
        List<SysRole> sysRoleList = sysRoleMapper.selectList(Wrappers.lambdaQuery(SysRole.class)
                .eq(SysRole::getStatus, StatusEnum.YES.getCode())
                .orderByAsc(SysRole::getSort));
        return BeanUtil.copyToList(sysRoleList, SysRoleVO.class);
    }

    private Boolean checkUniqueRoleCode(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysRole entity = sysRoleMapper.selectOne(Wrappers.lambdaQuery(SysRole.class).eq(SysRole::getRoleCode, value));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

    private Boolean checkUniqueRoleName(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysRole entity = sysRoleMapper.selectOne(Wrappers.lambdaQuery(SysRole.class).eq(SysRole::getRoleName, value));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

}
